package ca.scotthyndman.as2haxe;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collection;
import java.util.Properties;

import org.asdt.core.dom.ASANTLRParser;
import org.eclipse.jface.text.Document;

import ca.scotthyndman.as2haxe.dom.ASCompilationUnit;
import ca.scotthyndman.as2haxe.dom.AST;

/**
 * Parses AS2 classes into a tree.
 */
public class ASTParser {

	private static ASANTLRParser parser;

	/**
	 * Builds an AST based on the provided class paths. One of the class paths
	 * must be the system Flash classes.
	 * 
	 * @param stdLib
	 *            The path to the root directory of the Flash standard library
	 *            intrinsics.
	 * @param classPaths
	 *            A set of class paths
	 * 
	 * @return The abstract syntax tree.
	 * @throws IOException
	 */
	public static AST buildAST(String stdLib, Collection<String> classPaths)
			throws Exception {
		parser = new ASANTLRParser();

		//
		// Parse the standard library
		//
		Properties stdLibProps = new Properties();
		stdLibProps.put(Constants.PROP_DO_NOT_OUTPUT, true);
		parseDirectory(new File(stdLib), stdLibProps);
		
		//
		// Parse all the classes
		//
		for (String cp : classPaths) {
			parseDirectory(new File(cp), null);
		}
		
		//
		// Add container haXe classes
		//
		APIMapper.addHaxeContainerClasses(parser.getAST());

		//
		// Expose and link the bindings
		//
		parser.getAST().exposeBindings();
		parser.getAST().linkBindings();
		
		//
		// Return the tree
		//
		return parser.getAST();
	}

	/**
	 * Parses the contents of the directory recursively.
	 * 
	 * @param dir
	 *            The directory to parse.
	 * @param additionalInfo
	 *            Additional info added to each node in the tree
	 * @throws IOException
	 */
	private static void parseDirectory(File dir, Properties additionalInfo)
			throws Exception {
		for (File f : dir.listFiles()) {
			if (f.isHidden()) {
				continue;
			}

			if (f.isDirectory()) {
				parseDirectory(f, additionalInfo);
			} else if (f.getName().endsWith(".as")) {
				parseFile(f, additionalInfo);
			}
		}
	}

	/**
	 * Parses the contents of an actionscript file.
	 * 
	 * @param file
	 *            The file to parse.
	 * @param additionalInfo
	 *            Additional information to add to the type
	 * @throws IOException
	 */
	private static void parseFile(File file, Properties additionalInfo)
			throws Exception {
		BufferedReader reader = new BufferedReader(new FileReader(file));
		StringBuffer buf = new StringBuffer();
		String line = null;
		while ((line = reader.readLine()) != null) {
			buf.append(line);
			buf.append("\n");
		}
		reader.close();

		Document doc = new Document(buf.toString());
		ASCompilationUnit cunit = parser.getDom(doc);

		if (additionalInfo != null) {
			cunit.getExtraInfo().putAll(additionalInfo);
		}
	}
}
